package org.rcy.framework.data.config.mybatis;

import org.apache.ibatis.session.ExecutorType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * @author 吴康桥
 * @Description
 * @date 2022/9/29 14:10
 */

@ConfigurationProperties(MybatisProperties.PREFIX)
public class MybatisProperties implements BeanFactoryAware {
	public static final String PREFIX = "rcy.mybatis";
	public static final String TYPE_ALIASES = "rcy.mybatis.typeAliases";
	private static final String CONFIG_LOCATION = "classpath:mybatis-config.xml";

	private BeanFactory beanFactory;

	private String[] basePackages;

	/**
	 * Location of MyBatis xml config file.
	 */
	private String configLocation = CONFIG_LOCATION;

	/**
	 * Locations of MyBatis mapper files.
	 */
	private String[] mapperLocations;

	/**
	 * Packages to search type aliases. (Package delimiters are ",; \t\n")
	 */
	private String typeAliasesPackage;

	private Class<?>[] typeAliases = {};

	/**
	 * Packages to search for type handlers. (Package delimiters are ",; \t\n")
	 */
	private String typeHandlersPackage;

	/**
	 * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}.
	 */
	private ExecutorType executorType = ExecutorType.SIMPLE;

	/**
	 * 若不设置basePackages值，将返回@SpringBootApplication注解类所在的包</br>
	 * 如果@SpringBootApplication注解的包名含有”bootstrap“则自动去除”.bootstrap“
	 * 默认只需把@SpringBootApplication所在的类放在上级的包中或者bootstrap包中即可
	 */
	public String[] getBasePackages() {
		if (basePackages != null) {
			return basePackages;
		}

		try {
			//basePackages.add(ClassUtils.getPackageName(declaringClass));
			List<String> autoPackages = AutoConfigurationPackages.get(beanFactory);
			List<String> packages = new ArrayList<String>();
			for(String pkg:autoPackages) {
				packages.add(pkg.replace(".bootstrap", ""));
			}
			return StringUtils.toStringArray(packages);
		} catch (Exception e) {
			return new String[] {};
		}
	}

	public void setBasePackages(String[] basePackages) {
		this.basePackages = basePackages;
	}

	public String getTypeAliasesPackage() {
		return typeAliasesPackage == null ? joinedPackages() : typeAliasesPackage;
	}

	public String getTypeHandlersPackage() {
		return typeHandlersPackage == null ? joinedPackages() : typeHandlersPackage;
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		this.beanFactory = beanFactory;
	}

	public String getConfigLocation() {
		return configLocation;
	}

	public void setConfigLocation(String configLocation) {
		this.configLocation = configLocation;
	}

	public String[] getMapperLocations() {
		return mapperLocations;
	}

	public void setMapperLocations(String[] mapperLocations) {
		this.mapperLocations = mapperLocations;
	}

	public void setTypeAliasesPackage(String typeAliasesPackage) {
		this.typeAliasesPackage = typeAliasesPackage;
	}

	public void setTypeHandlersPackage(String typeHandlersPackage) {
		this.typeHandlersPackage = typeHandlersPackage;
	}

	public ExecutorType getExecutorType() {
		return executorType;
	}

	public void setExecutorType(ExecutorType executorType) {
		this.executorType = executorType;
	}

	private String joinedPackages() {
		StringBuilder builder = new StringBuilder();
		for(String pkg:getBasePackages()) {
			builder.append(",").append(pkg);
		}
		return builder.substring(1);
	}

	public Class<?>[] getTypeAliases() {
		String settingAliases = System.getProperty(TYPE_ALIASES);
		if(settingAliases !=null) {
			List<Class<?>> aliasesList = new ArrayList<Class<?>>(Arrays.asList(typeAliases));
			String[] aliases = settingAliases.split(",");
			for(String aliase:aliases) {
				try {
					aliasesList.add(Class.forName(aliase));
				} catch (ClassNotFoundException e) { }
			}
			return aliasesList.toArray(new Class<?>[aliasesList.size()]);
		}
		return typeAliases;
	}

	public void setTypeAliases(Class<?>[] typeAliases) {
		this.typeAliases = typeAliases;
	}

}
